﻿using System.CodeDom.Compiler;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace System {

	#region Usings

	#endregion

	/// <summary>
	/// 	Adds behaviors to the <c>Object</c> class.
	/// </summary>
	public static class ObjectExtension {
		/// <summary>
		/// 	Serializes the specified obj.
		/// </summary>
		/// <param name = "obj">The obj.</param>
		/// <returns></returns>
		public static string Serialize ( this object obj ) {
			if ( obj == null ) {
				throw new ArgumentNullException ( );
			}

			XmlSerializer s = new XmlSerializer(obj.GetType());
			using (TextWriter w = new StringWriter())
			{
				s.Serialize(w, obj);
				return w.ToString();
			}
		}

		public static TResult With<TInput, TResult> ( this TInput o, Func<TInput, TResult> evaluator )
			where TResult : class
			where TInput : class {
			if (o == null) {
				return null;
			}

			return evaluator ( o );
		}

		public static TResult Return<TInput, TResult> ( this TInput input, Func<TInput, TResult> evaluator, Func<TResult> defaultValueOnNullInput )
			where TInput : class {

			return input.Return ( evaluator, defaultValueOnNullInput, obj => obj == null );
		}

		public static TResult Return<TInput, TResult> ( this TInput o, Func<TInput, TResult> evaluator, Func<TResult> failureValue, Predicate<TInput> failureEvaluator ) {
			if (failureEvaluator ( o )) {
				return failureValue();
			}

			return evaluator ( o );
		}

		public static TInput Do<TInput> ( this TInput o, Action<TInput> action )
			where TInput : class {
			if (o == null) {
				return null;
			}

			action ( o );

			return o;
		}

		public static TInput If<TInput> ( this TInput o, Func<TInput, bool> evaluator )
			where TInput : class {
			if (o == null) return null;
			return evaluator ( o ) ? o : null;
		}

		public static TInput Unless<TInput> ( this TInput o, Func<TInput, bool> evaluator )
		  where TInput : class {
			if (o == null) return null;
			return evaluator ( o ) ? null : o;
		}
	}
}